<?php

/*
  [示例1:图片验证码的使用]

  ---------- reg.html的代码如下 ---------------
  <form method=post action="/reg/register">
  <img src="/reg/code" onclick="this.src='/reg/code" />
  输入图片中的字符,不区分大小写,看不清请点击图片更换:
  <input type="text" name="code">
  <input type="submit" value="提交">
  </form>

  ---------- reg.php 控制器的代码如下 ---------
  public function register()
  {
  echo \Image::chkVerify() ? '验证码正确' : '验证码错误';
  }
  public funciton code()
  {
  \Image::imgVerify();
  }
  ------------------------------------------

  [示例:2图片处理]
  ------------------------------------------
  // 输出图片的信息
  print_r(Image::getInfo('/home/a.jpg'));
  // 生成 a.jpg 的缩略图,宽度:100 高度:120
  \Image::thumbImg('a.jpg','a-thumb.jpg',100,120);

  [注意]
  1:在 Uploadfile 文件上传工具中已经包括了该缩略图方法的调用,详情请看文件上传工具的使用.

 */

class Image {

    /**
     * 防止类实例化或被复制
     *
     */
    private function __construct() {
        
    }

    private function __clone() {
        
    }

    /**
     * 得到图片的信息
     *
     * @param $imgFile:文件文件名
     */
    static public function getInfo($imgFile) {
        $imageInfo = getimagesize($imgFile);
        if ($imageInfo !== false) {
            $imageType = strtolower(substr(image_type_to_extension($imageInfo[2]), 1));
            $imageSize = filesize($imgFile);
            $info = array(
                "width" => $imageInfo[0],
                "height" => $imageInfo[1],
                "type" => $imageType,
                "size" => $imageSize,
                "mime" => $imageInfo['mime']
            );
            return $info;
        } else {
            return false;
        }
    }

    /**
     * 生成缩略图
     *
     * 缩略图会根据源图的比例进行缩略的，生成的缩略图格式是 JPG
     *
     * @param $srcfile:源文件名
     * @param $dstfile:生成缩略图的文件名,扩展名必需为 ".jpg"
     * @param $thumbWidth:缩略图最大宽度
     * @param $thumbHeight:缩略图最大高度
     * @param $keepscalerate 是否保持图片比例
     */
    static public function thumbImg($srcfile, $dstfile, $thumbWidth, $thumbHeight, $keepscalerate = true) {
        // 缩略图大小
        $tow = $thumbWidth;
        $toh = $thumbHeight;
        // 是否处理原图
        $make_max = 0;
        $maxtow = $thumbWidth;
        $maxtoh = $thumbHeight;

        // 获取图片信息
        $im = '';
        if ($data = getimagesize($srcfile)) {
            if ($data[2] == 1) {
                $make_max = 0; //gif不处理
                if (function_exists("imagecreatefromgif")) {
                    $im = imagecreatefromgif($srcfile);
                }
            } elseif ($data[2] == 2) {
                if (function_exists("imagecreatefromjpeg")) {
                    $im = imagecreatefromjpeg($srcfile);
                }
            } elseif ($data[2] == 3) {
                if (function_exists("imagecreatefrompng")) {
                    $im = imagecreatefrompng($srcfile);
                }
            }
        }
        if (!$im)
            return '';

        $srcw = imagesx($im);
        $srch = imagesy($im);

        $towh = $tow / $toh;
        $srcwh = $srcw / $srch;
        if ($towh <= $srcwh) {
            $ftow = $tow;
            $fmaxtow = $maxtow;

            if ($keepscalerate) {
                $ftoh = $ftow * ($srch / $srcw);
                $fmaxtoh = $fmaxtow * ($srch / $srcw);
            } else {
                $ftoh = $toh;
                $fmaxtoh = $maxtoh;
            }
        } else {
            $ftoh = $toh;
            $fmaxtoh = $maxtoh;

            if ($keepscalerate) {
                $ftow = $ftoh * ($srcw / $srch);
                $fmaxtow = $fmaxtoh * ($srcw / $srch);
            } else {
                $ftow = $tow;
                $fmaxtow = $maxtow;
            }
        }
        if ($srcw <= $maxtow && $srch <= $maxtoh) {
            $make_max = 0; // 不处理
        }
        if ($srcw > $tow || $srch > $toh) {
            if (function_exists("imagecreatetruecolor") && function_exists("imagecopyresampled") && @$ni = imagecreatetruecolor($ftow, $ftoh)) {
                imagecopyresampled($ni, $im, 0, 0, 0, 0, $ftow, $ftoh, $srcw, $srch);
                // 大图片
                if ($make_max && @$maxni = imagecreatetruecolor($fmaxtow, $fmaxtoh)) {
                    imagecopyresampled($maxni, $im, 0, 0, 0, 0, $fmaxtow, $fmaxtoh, $srcw, $srch);
                }
            } elseif (function_exists("imagecreate") && function_exists("imagecopyresized") && @$ni = imagecreate($ftow, $ftoh)) {
                imagecopyresized($ni, $im, 0, 0, 0, 0, $ftow, $ftoh, $srcw, $srch);
                // 大图片
                if ($make_max && @$maxni = imagecreate($fmaxtow, $fmaxtoh)) {
                    imagecopyresized($maxni, $im, 0, 0, 0, 0, $fmaxtow, $fmaxtoh, $srcw, $srch);
                }
            } else {
                return '';
            }
            // -
            if (function_exists('imagejpeg')) {
                imagejpeg($ni, $dstfile);
                // 大图片
                if ($make_max) {
                    imagejpeg($maxni, $srcfile);
                }
            } elseif (function_exists('imagepng')) {
                imagepng($ni, $dstfile);
                // 大图片
                if ($make_max) {
                    imagepng($maxni, $srcfile);
                }
            }
            imagedestroy($ni);
            if ($make_max) {
                imagedestroy($maxni);
            }
        }
        imagedestroy($im);
        return file_exists($dstfile);
    }

    static public function imgVerifyHighLight() {
        return self::imgVerify(4, 3, 'png', 200, 80, true);
    }

    /**
     * 生成图片验证码
     *
     * @param int $length :验证码长度
     * @param int $mode :模型 0:数字 1:小写字母 2:大写字母 3:字母与数字组合
     * @param string $type :指定图片类型，一般用默认值.
     * @param int $width :图片宽
     * @param int $height :图片高
     */
    static public function imgVerify($length = 4, $mode = 3, $type = 'png', $width = 200, $height = 80, $highlight = false) {
        // 生成随机数保存在 SESSION 中
        $randval = randString($length, $mode);

        // 加密验证码并保存
        if (!$secret = Sys::getCfg('base_secret_key')) {
            echo 'error';
        }
        
        $key = md5(strtolower($randval) . $secret);

        $width = ($length * 9 + 10) > $width ? $length * 9 + 10 : $width;
        if ($type != 'gif' && function_exists('imagecreatetruecolor')) {
            $im = @imagecreatetruecolor($width, $height);
        } else {
            $im = @imagecreate($width, $height);
        }

        $backColor = imagecolorallocatealpha($im, 0, 0, 0, 127); // 背景透明

        imagealphablending($im, false); //关闭混合模式，以便透明颜色能覆盖原画板    

        @imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $backColor);

        // 干扰线
        for ($i = 0; $i < 10; $i++) {
            $lineColor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            imagearc($im, mt_rand(-10, $width), mt_rand(-10, $height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $lineColor);
        }
        // 干扰点
        for ($i = 0; $i < 25; $i++) {
            $pointColor = imagecolorallocate($im, 246, 244, 249);
            imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $pointColor);
        }

        for ($i = 0; $i < strlen($randval); $i++) {
            if ($highlight) {
                $stringColor = imagecolorallocate($im, mt_rand(100, 230), mt_rand(100, 230), mt_rand(100, 230));
            } else {
                $stringColor = imagecolorallocate($im, mt_rand(0, 200), mt_rand(0, 120), mt_rand(0, 120));
            }
            // 替换imagestring，以便可以设置字体大小
            @imagettftext($im, 40, mt_rand(-45, 45), 25 + $i * 40, $height - 20, $stringColor, __DIR__ . '/arial.ttf', $randval[$i]);
        }

        imagesavealpha($im, true); //设置保存PNG时保留透明通道信息  

        $ImageFun = 'Image' . $type;
        $ImageFun($im);
        imagedestroy($im);

        if (session_status() == PHP_SESSION_ACTIVE) {
            Session::set('captcha_key', $key);
        }

        header("Content-type: image/" . $type);

        // 返回加密后的验证码
        return $key;
    }

    /**
     * 检测输入的验证码是否正确
     */
    static public function chkVerify($captcha_code, $captcha_key = null) {
        $key = md5(strtolower($captcha_code) . Sys::getCfg('base_secret_key'));
        if ($captcha_key) {
            return $captcha_key == $key;
        }
        return Session::get('captcha_key') == $key;
    }

    /**
     * 合成图片
     * 
     * @param array $config
     * 
     * $config = array(
     *     'image' => array(
     *         array(
     *             'url' => 'qrcode.png', //二维码资源
     *             'stream' => 0, // url的内容是否是字符串图像流（不是图片地址，file_get_contents(image_file)）
     *             'dst_x' => 264,
     *             'dst_y' => 800,
     *             'src_x' => 0,
     *             'src_y' => 0,
     *             'src_w' => 225,
     *             'src_h' => 225,
     *             'opacity' => 100,
     *         ),
     *         array(
     *             'url' => 'top.jpg', //用户头像
     *             'stream' => 0, // url的内容是否是字符串图像流（不是图片地址，file_get_contents(image_file)）
     *             'dst_x' => 50,
     *             'dst_y' => 50,
     *             'src_x' => 0,
     *             'src_y' => 0,
     *             'src_w' => 100,
     *             'src_h' => 100,
     *             'opacity' => 100,
     *         ),
     *     ),
     *     'text' => array(
     *         array(
     *             'text' => 'rookie1',
     *             'dst_x' => 48,
     *             'dst_y' => 183,
     *             'fontSize' => 22, //字号
     *             'fontColor' => '255,255,255', //字体颜色
     *             'angle' => 0,
     *             'fontPath' => __DIR__ . '/simsun.ttf', //当前文件下的字体，注意要支持中文哦，否则会乱码的
     *         ),
     *         array(
     *             'text' => 'rookie2',
     *             'dst_x' => 48,
     *             'dst_y' => 183,
     *             'fontSize' => 22, //字号
     *             'fontColor' => '255,255,255', //字体颜色
     *             'angle' => 0,
     *             'fontPath' => __DIR__ . '/simsun.ttf', //当前文件下的字体，注意要支持中文哦，否则会乱码的
     *         ),
     *     ),
     *     'background' => 'poster_bg.jpg' //背景图
     * );
     * 
     * @param string $filename
     * @return string
     */
    static public function composite($config = array(), $filename = null) {
        //如果要看报什么错，可以先注释调这个header
        if (empty($filename))
            header("content-type: image/png");
        $imageDefault = array(
            'dst_x' => 0,
            'dst_y' => 0,
            'src_x' => 0,
            'src_y' => 0,
            'src_w' => 100,
            'src_h' => 100,
            'opacity' => 100
        );
        $textDefault = array(
            'text' => '',
            'dst_x' => 0,
            'dst_y' => 0,
            'fontSize' => 32, //字号
            'fontColor' => '255,255,255', //字体颜色
            'fontPath' => 'arial.ttf',
            'angle' => 0,
        );
        $background = $config['background']; //海报最底层得背景
        //背景方法
        $backgroundInfo = getimagesize($background);
        $backgroundFun = 'imagecreatefrom' . image_type_to_extension($backgroundInfo[2], false);
        $background = $backgroundFun($background);
        $backgroundWidth = imagesx($background);  //背景宽度
        $backgroundHeight = imagesy($background);  //背景高度
        $imageRes = imageCreatetruecolor($backgroundWidth, $backgroundHeight);
        $color = imagecolorallocate($imageRes, 0, 0, 0);
        imagefill($imageRes, 0, 0, $color);
        // imageColorTransparent($imageRes, $color);  //颜色透明
        imagecopyresampled($imageRes, $background, 0, 0, 0, 0, imagesx($background), imagesy($background), imagesx($background), imagesy($background));
        //处理了图片
        if (!empty($config['image'])) {
            foreach ($config['image'] as $key => $val) {
                $val = array_merge($imageDefault, $val);
                $info = getimagesize($val['url']);
                $function = 'imagecreatefrom' . image_type_to_extension($info[2], false);
                if ($val['stream']) {   //如果传的是字符串图像流
                    $info = getimagesizefromstring($val['url']);
                    $function = 'imagecreatefromstring';
                }
                $res = $function($val['url']);
                $resWidth = $info[0];
                $resHeight = $info[1];
                //建立画板 ，缩放图片至指定尺寸
                $canvas = imagecreatetruecolor($val['src_w'], $val['src_h']);
                imagefill($canvas, 0, 0, $color);
                //关键函数，参数（目标资源，源，目标资源的开始坐标x,y, 源资源的开始坐标x,y,目标资源的宽高w,h,源资源的宽高w,h）
                imagecopyresampled($canvas, $res, 0, 0, 0, 0, $val['src_w'], $val['src_h'], $resWidth, $resHeight);
                $val['dst_x'] = $val['dst_x'] < 0 ? $backgroundWidth - abs($val['dst_x']) - $val['src_w'] : $val['dst_x'];
                $val['dst_y'] = $val['dst_y'] < 0 ? $backgroundHeight - abs($val['dst_y']) - $val['src_h'] : $val['dst_y'];
                //放置图像
                imagecopymerge($imageRes, $canvas, $val['dst_x'], $val['dst_y'], $val['src_x'], $val['src_y'], $val['src_w'], $val['src_h'], $val['opacity']); //左，上，右，下，宽度，高度，透明度
            }
        }
        //处理文字
        if (!empty($config['text'])) {
            foreach ($config['text'] as $key => $val) {
                $val = array_merge($textDefault, $val);
                list($R, $G, $B) = explode(',', $val['fontColor']);
                $fontColor = imagecolorallocate($imageRes, $R, $G, $B);
                $val['dst_x'] = $val['dst_x'] < 0 ? $backgroundWidth - abs($val['dst_x']) : $val['dst_x'];
                $val['dst_y'] = $val['dst_y'] < 0 ? $backgroundHeight - abs($val['dst_y']) : $val['dst_y'];
                imagettftext($imageRes, $val['fontSize'], $val['angle'], $val['dst_x'], $val['dst_y'], $fontColor, $val['fontPath'], $val['text']);
            }
        }

        //保存到本地
        $res = imagejpeg($imageRes, $filename, 90);
        imagedestroy($imageRes);
        if (!$res)
            return false;
        return $filename;
    }
}
